package com.moss.cloud.common.core.utils;

import cn.hutool.core.net.NetUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 自定义分布式雪花算法，避免始终回拨
 *
 * @author 瑾年
 * @date 2023年8月14日
 */
@Slf4j
public class MossSnowFlake {
    /**
     * 2020-01-01 00:00:00 对应的秒
     */
    private final static long beginTs = 1577808000L;

    /**
     * 顺序号最大值（大约419万）
     */
    private final static long maxSequence = 4194300L;

    /**
     * 最大时钟回拨(秒)，4194秒，大约69分钟
     */
    private final static long maxTimeback = 4194L;

    private long lastTs = 0L;

    private long processId;
    private int processIdBits = 10;

    private long sequence = 1L;
    private int sequenceBits = 22;

    MossSnowFlake() {
        String ipAddr = NetUtil.getLocalhostStr();
        Long workerId = NetUtil.ipv4ToLong(ipAddr);
        workerId = workerId % 1024;
        this.processId = workerId;
    }

    /**
     * 根据已知的workerId和流水号进行初始化
     *
     * @param workerId
     * @param sequence
     */
    private MossSnowFlake(Long workerId, Long sequence) {
        this.processId = workerId;
        this.sequence = sequence;
    }

    /**
     * 获取当前时间(秒为单位)
     *
     * @return
     */
    private long timeGen() {
        return System.currentTimeMillis() / 1000;
    }

    /**
     * 生成一个Id
     *
     * @return
     */
    synchronized long nextId() {
        // 获取当前时间(秒为单位)
        long ts = timeGen();
        // 刚刚生成的时间戳比上次的时间戳还小，出错
        long tempDiff = lastTs - ts;
        if (tempDiff >= maxTimeback) {
            log.warn("时钟回拨超过4194秒，存在Id重复风险");
        }
        sequence = sequence + 1;
        if (sequence >= maxSequence) {
            sequence = 1;
        }
        // 更新lastTs时间戳
        lastTs = ts;
        long timeDiff = ts - beginTs;
        return (timeDiff << (processIdBits + sequenceBits)) | (processId << sequenceBits) | sequence;
    }
}
